from flask import Flask, render_template, request, jsonify, send_file
import itertools
import os
import json
from datetime import datetime
from PIL import Image, ImageDraw, ImageFont
import requests
import random
import time
from io import BytesIO
import zipfile

app = Flask(__name__)

# 中文字体搜索路径
FONT_PATHS = [
    "/usr/share/fonts/wqy-microhei/wqy-microhei.ttc",
    "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
    "/Library/Fonts/PingFang.ttc",
    "C:/Windows/Fonts/simhei.ttf",
    "simhei.ttf"
]

# 胜平负选项颜色配置
OPTION_COLORS = {
    "3": "#ffeeee",
    "1": "#ffffee",
    "0": "#eeffee"
}
SELECTED_BORDER_COLOR = (255, 0, 0)
SELECTED_BORDER_WIDTH = 3


class Lottery9FromN:
    def __init__(self):
        self.default_data_url = "https://webapi.sporttery.cn/gateway/lottery/getFootBallMatchV1.qry?param=90,0&lotteryDrawNum=&sellStatus=0&termLimits=10"
        self.user_data_url = None
        self.matches = []
        self.match_choices = {}  # {match_id: {"3": False, "1": False, "0": False}}
        self.generated_combinations = []
        self.refresh_data()

    def get_current_data_url(self):
        return self.user_data_url if self.user_data_url else self.default_data_url

    def set_data_url(self, url):
        if url and url.strip():
            self.user_data_url = url.strip()
            return True, "链接已保存"
        return False, "请输入有效的链接"

    def _init_match_data(self):
        try:
            url = self.get_current_data_url().strip()
            if not url:
                raise Exception("数据链接为空，请输入有效链接")

            headers = {
                "User-Agent": random.choice([
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Safari/605.1.15"
                ]),
                "Accept": "application/json, text/javascript, */*; q=0.01",
                "X-Requested-With": "XMLHttpRequest"
            }

            response = None
            for _ in range(3):
                try:
                    time.sleep(random.uniform(0.5, 1.5))
                    response = requests.get(url, headers=headers, timeout=10)
                    if response.status_code == 200:
                        break
                except Exception as e:
                    print(f"请求失败: {e}")
                    continue

            if not response or response.status_code != 200:
                raise Exception(f"请求失败，状态码: {response.status_code if response else '无响应'}")

            try:
                json_data = response.json()
            except Exception as e:
                raise Exception(f"解析JSON失败: {str(e)}")

            if not json_data.get("success", False):
                raise Exception(f"API返回错误: {json_data.get('errorMessage', '未知错误')}")

            sfc_match = json_data.get("value", {}).get("sfcMatch", {})
            match_list = sfc_match.get("matchList", [])

            if not match_list:
                raise Exception("API中未包含比赛数据")

            matches = []
            for match in match_list[:14]:
                try:
                    match_num = match.get("matchNum", len(matches) + 1)
                    league = match.get("matchName", "未知联赛")

                    start_time = match.get("startTime", "")
                    if len(start_time) >= 16:
                        date_part = start_time[5:10]
                        time_part = start_time[11:16]
                        match_time = f"{date_part} {time_part}"
                    else:
                        match_time = start_time or "00:00"

                    home_team = match.get("masterTeamName", f"主队{match_num}")
                    away_team = match.get("guestTeamName", f"客队{match_num}")
                    odds3 = float(match.get("h", 1.5 + random.random())) if match.get("h") else round(1.5 + random.random(), 2)
                    odds1 = float(match.get("d", 3.5 + random.random())) if match.get("d") else round(3.5 + random.random(), 2)
                    odds0 = float(match.get("a", 5.5 + random.random() * 2)) if match.get("a") else round(5.5 + random.random() * 2, 2)

                    matches.append({
                        "id": match_num,
                        "league": league,
                        "time": match_time,
                        "home": home_team,
                        "away": away_team,
                        "odds3": round(odds3, 2),
                        "odds1": round(odds1, 2),
                        "odds0": round(odds0, 2)
                    })
                except Exception as e:
                    current_id = len(matches) + 1
                    print(f"解析第{current_id}场比赛失败: {e}")
                    matches.append(self._get_default_single_match(current_id))

            while len(matches) < 14:
                matches.append(self._get_default_single_match(len(matches) + 1))

            return matches[:14]

        except Exception as e:
            print(f"获取数据失败: {e}")
            return self._get_default_match_data()

    def _get_default_single_match(self, idx):
        return {
            "id": idx,
            "league": f"联赛{idx}",
            "time": f"08-{str(idx+10).zfill(2)} 20:00",
            "home": f"主队{idx}",
            "away": f"客队{idx}",
            "odds3": round(1.2 + random.random(), 2),
            "odds1": round(3.0 + random.random(), 2),
            "odds0": round(4.0 + random.random() * 3, 2)
        }

    def _get_default_match_data(self):
        return [self._get_default_single_match(i) for i in range(1, 15)]

    def refresh_data(self):
        self.matches = self._init_match_data()
        self.match_choices = {m["id"]: {"3": False, "1": False, "0": False} for m in self.matches}
        self.generated_combinations = []
        return self.matches

    def toggle_selection(self, match_id, result):
        if match_id in self.match_choices and result in ["3", "1", "0"]:
            self.match_choices[match_id][result] = not self.match_choices[match_id][result]
            return True
        return False

    def generate_combination_image(self, combination):
        combo_items = combination.split(", ")
        combo_dict = {}
        for item in combo_items:
            match_id, result = item.split(":")
            combo_dict[int(match_id)] = result

        combo_matches = [m for m in self.matches if m["id"] in combo_dict.keys()]
        if len(combo_matches) != 9:
            raise ValueError("组合包含的比赛数量不是9场")

        width = 800
        match_height = 80
        header_height = 50
        total_height = header_height + match_height * 9 + 20

        image = Image.new("RGB", (width, total_height), color="#ffffff")
        draw = ImageDraw.Draw(image)

        font = None
        for font_path in FONT_PATHS:
            if os.path.exists(font_path):
                try:
                    font = ImageFont.truetype(font_path, 14)
                    print(f"成功加载字体: {font_path}")  # 新增日志
                    break
                except Exception as e:
                    print(f"加载字体{font_path}失败: {e}")  # 新增日志
                    continue
        if not font:
            print("未找到任何可用字体，将使用默认字体（可能不支持中文）")  # 新增日志
            font = ImageFont.load_default()

        title = f"胜负彩任9组合 - {datetime.now().strftime('%Y%m%d')}"
        draw.text((width//2, header_height//2), title, font=font, fill="#333333", anchor="mm")

        for idx, match in enumerate(combo_matches):
            match_id = match["id"]
            selected_result = combo_dict[match_id]
            y_pos = header_height + 10 + idx * match_height

            draw.rectangle([(10, y_pos), (60, y_pos + match_height - 5)], fill="#f0f0f0")
            draw.rectangle([(60, y_pos), (180, y_pos + match_height - 5)], fill="#f0f0f0")
            draw.rectangle([(180, y_pos), (280, y_pos + match_height - 5)], fill="#f0f0f0")
            draw.rectangle([(280, y_pos), (480, y_pos + match_height - 5)], fill=OPTION_COLORS["3"])
            draw.rectangle([(480, y_pos), (600, y_pos + match_height - 5)], fill=OPTION_COLORS["1"])
            draw.rectangle([(600, y_pos), (800, y_pos + match_height - 5)], fill=OPTION_COLORS["0"])

            draw.text((35, y_pos + 10), str(match["id"]), font=font, fill="#333333", anchor="mm")
            draw.text((120, y_pos + 10), match["league"], font=font, fill="#333333", anchor="mm")
            draw.text((230, y_pos + 10), match["time"], font=font, fill="#333333", anchor="mm")

            home_text = f"{match['home']} ({match['odds3']})"
            draw.text((380, y_pos + 10), home_text, font=font, fill="#333333", anchor="mm")
            draw.text((540, y_pos + 10), f"平 ({match['odds1']})", font=font, fill="#333333", anchor="mm")

            away_text = f"{match['away']} ({match['odds0']})"
            draw.text((700, y_pos + 10), away_text, font=font, fill="#333333", anchor="mm")

            if selected_result == "3":
                draw.rectangle([(280, y_pos), (480, y_pos + match_height - 5)],
                               fill=(255, 0, 0))  # 纯红色填充
                # 绘制白色文字以提高对比度
                draw.text((380, y_pos + 10), home_text, font=font, fill="#ffffff", anchor="mm")
            elif selected_result == "1":
                draw.rectangle([(480, y_pos), (600, y_pos + match_height - 5)],
                               fill=(255, 0, 0))  # 纯红色填充
                draw.text((540, y_pos + 10), f"平 ({match['odds1']})", font=font, fill="#ffffff", anchor="mm")
            elif selected_result == "0":
                draw.rectangle([(600, y_pos), (800, y_pos + match_height - 5)],
                               fill=(255, 0, 0))  # 纯红色填充
                draw.text((700, y_pos + 10), away_text, font=font, fill="#ffffff", anchor="mm")
        return image

    def get_selected_matches(self):
        """获取所有选中的比赛及统计信息"""
        selected = []
        total_choices = 0
        for match in self.matches:
            match_id = match["id"]
            choices = self.match_choices.get(match_id, {})
            has_choice = any([choices["3"], choices["1"], choices["0"]])
            if has_choice:
                selected.append(match)
                total_choices += sum([1 for v in choices.values() if v])
                # 添加日志
                print(f"选中场次: {match_id}, 选择结果: {choices}")  # 新增日志

        selected_count = len(selected)
        avg_choices = total_choices / selected_count if selected_count > 0 else 0

        # 构建详细选中信息
        detailed_selected = []
        for match in selected:
            match_id = match["id"]
            choices = self.match_choices.get(match_id, {})
            for result, selected_flag in choices.items():
                if selected_flag:
                    detailed_selected.append({
                        "id": match_id,
                        "result": result,
                        "league": match["league"],
                        "home": match["home"],
                        "away": match["away"]
                    })

        return detailed_selected, selected_count, avg_choices

    def combination(self, n, k):
        if n < k or k < 0:
            return 0
        if k == 0 or k == n:
            return 1
        k = min(k, n - k)
        result = 1
        for i in range(1, k + 1):
            result = result * (n - k + i) // i
        return result

    def generate_combinations(self):
        try:
            selected_matches, count, _ = self.get_selected_matches()
            if count < 9:
                return False, f"至少选择9场比赛，当前选择了{count}场"

            indices = list(range(len(selected_matches)))
            combinations = list(itertools.combinations(indices, 9))

            self.generated_combinations = []
            for combo in combinations:
                combo_str = ", ".join([
                    f"{selected_matches[i]['id']}:{selected_matches[i]['result']}"
                    for i in combo
                ])
                self.generated_combinations.append(combo_str)

            return True, f"成功生成{len(self.generated_combinations)}组组合"
        except Exception as e:
            return False, f"生成组合失败: {str(e)}"

    def export_combinations_as_zip(self):
        try:
            zip_buffer = BytesIO()
            with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zipf:
                # 限制最多100个组合，避免内存溢出
                max_export = min(100, len(self.generated_combinations))
                for i in range(max_export):
                    combo = self.generated_combinations[i]
                    img = self.generate_combination_image(combo)
                    img_buffer = BytesIO()
                    img.save(img_buffer, format="PNG")
                    img_buffer.seek(0)
                    zipf.writestr(f"combination_{i+1}.png", img_buffer.read())

            zip_buffer.seek(0)
            return zip_buffer, "打包成功"
        except Exception as e:
            return None, f"打包失败: {str(e)}"


# 创建全局实例（解决状态丢失问题）
lottery = Lottery9FromN()


@app.route('/')
def index():
    return render_template(
        'index.html',
        matches=lottery.matches,
        current_url=lottery.get_current_data_url(),
        issue=f"第{datetime.now().strftime('%Y%m%d')}期"
    )

@app.route('/toggle', methods=['POST'])
def toggle():
    data = request.get_json()
    # 修复1：将match_id转为整数
    match_id = int(data.get('match_id', ''))
    result = data.get('result')

    if lottery.toggle_selection(match_id, result):
        _, selected_count, _ = lottery.get_selected_matches()
        combo_count = lottery.combination(selected_count, 9) if selected_count >=9 else 0
        total_bets = 0

        if selected_count >=9:
            total_bets = 1
            for match in lottery.matches:
                mid = match["id"]
                choices = lottery.match_choices.get(mid, {})
                if any(choices.values()):  # 只计算选中的场次
                    total_bets *= sum([1 for v in choices.values() if v])

        return jsonify({
            "status": "success",
            "selected_count": selected_count,
            "combo_count": combo_count,
            "total_bets": total_bets
        })
    return jsonify({"status": "error", "message": "切换选择失败"})

@app.route('/set-url', methods=['POST'])
def set_url():
    data = request.get_json()
    url = data.get('url', '')
    success, message = lottery.set_data_url(url)
    return jsonify({
        "status": "success" if success else "error",
        "message": message,
        "url": lottery.get_current_data_url()
    })

@app.route('/refresh', methods=['POST'])
def refresh():
    try:
        # 刷新前先清空选择状态
        lottery.match_choices = {m["id"]: {"3": False, "1": False, "0": False} for m in lottery.matches}
        lottery.generated_combinations = []  # 同时清空生成的组合
        matches = lottery.refresh_data()
        return jsonify({
            "status": "success",
            "message": "数据刷新成功",
            "matches": matches
        })
    except Exception as e:
        return jsonify({"status": "error", "message": f"刷新失败: {str(e)}"})

@app.route('/generate', methods=['POST'])
def generate():
    success, message = lottery.generate_combinations()
    count = len(lottery.generated_combinations) if success else 0
    return jsonify({
        "status": "success" if success else "error",
        "message": message,
        "count": count
    })

@app.route('/load-combinations/<int:page>', methods=['GET'])
def load_combinations(page):
    per_page = 10
    total = len(lottery.generated_combinations)
    total_pages = (total + per_page - 1) // per_page

    start = (page - 1) * per_page
    end = start + per_page
    combinations = lottery.generated_combinations[start:end]

    return jsonify({
        "status": "success",
        "combinations": combinations,
        "current_page": page,
        "total_pages": total_pages,
        "total_count": total
    })

@app.route('/export-image')
def export_image():
    if not lottery.generated_combinations:
        return jsonify({"status": "error", "message": "没有可导出的组合"}), 400

    try:
        if len(lottery.generated_combinations) == 1:
            first_combination = lottery.generated_combinations[0]
            image = lottery.generate_combination_image(first_combination)
            img_buffer = BytesIO()
            image.save(img_buffer, format="PNG")
            img_buffer.seek(0)
            return send_file(
                img_buffer,
                mimetype='image/png',
                as_attachment=True,
                download_name=f"组合_{datetime.now().strftime('%Y%m%d')}.png"
            )

        zip_buffer, message = lottery.export_combinations_as_zip()
        if zip_buffer:
            return send_file(
                zip_buffer,
                mimetype='application/zip',
                as_attachment=True,
                download_name=f"组合_{datetime.now().strftime('%Y%m%d')}.zip"
            )

        return jsonify({"status": "error", "message": "生成图片失败"}), 500

    except Exception as e:
        return jsonify({"status": "error", "message": f"导出失败: {str(e)}"}), 500

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

if __name__ == '__main__':
    # 生产环境请将debug改为False，并配置合适的host和port
    app.run(host='0.0.0.0', port=5000, debug=False)